package rsa;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

import javax.crypto.Cipher;

import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.pkcs.RSAPrivateKeyStructure;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.core.io.ClassPathResource;

import sun.misc.BASE64Decoder;

public class RSAUtil {


	public static RSAPublicKey loadPublicKey(InputStream in) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(in));
		String readLine = null;
		StringBuilder sb = new StringBuilder();
		while ((readLine = br.readLine()) != null) {
			if (readLine.charAt(0) == '-') {
				continue;
			} else {
				sb.append(readLine);
				sb.append('\r');
			}
		}
		return loadPublicKey(sb.toString());

	}


	public static RSAPublicKey loadPublicKey(String publicKeyStr) throws Exception {
		BASE64Decoder base64Decoder = new BASE64Decoder();
		byte[] buffer = base64Decoder.decodeBuffer(publicKeyStr);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
		RSAPublicKey publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
		return publicKey;
	}

	public static RSAPrivateKey loadPrivateKey_pkcs_1(InputStream in) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(in));
		String readLine = null;
		StringBuilder sb = new StringBuilder();
		while ((readLine = br.readLine()) != null) {
			if (readLine.charAt(0) == '-') {
				continue;
			} else {
				sb.append(readLine);
				sb.append('\r');
			}
		}
		return loadPrivateKey_pkcs_1(sb.toString());
	}

	public static RSAPrivateKey loadPrivateKey_pkcs_1(String privateKeyStr) throws Exception {
		byte[] asn1PrivateKeyBytes = org.apache.commons.codec.binary.Base64
				.decodeBase64(privateKeyStr.getBytes("US-ASCII"));
		RSAPrivateKeyStructure asn1PrivKey = new RSAPrivateKeyStructure(
				(ASN1Sequence) ASN1Sequence.fromByteArray(asn1PrivateKeyBytes));
		RSAPrivateKeySpec rsaPrivKeySpec = new RSAPrivateKeySpec(asn1PrivKey.getModulus(),
				asn1PrivKey.getPrivateExponent());
		KeyFactory kf = KeyFactory.getInstance("RSA");
		RSAPrivateKey privKey = (RSAPrivateKey) kf.generatePrivate(rsaPrivKeySpec);
		return privKey;
	}

	/**
	 * 加密过程
	 * 
	 * @param publicKey     公钥
	 * @param plainTextData 明文数据
	 * @return
	 * @throws Exception 加密过程中的异常信息
	 */
	public byte[] encryptByPublic(RSAPublicKey publicKey, byte[] plainTextData) throws Exception {
		if (publicKey == null) {
			throw new Exception("加密公钥为空, 请设置");
		}
		Cipher cipher = null;

		cipher = Cipher.getInstance("RSA", new BouncyCastleProvider());
		cipher.init(Cipher.ENCRYPT_MODE, publicKey);
		byte[] output = cipher.doFinal(plainTextData);
		return output;

	}
	
	public static byte[] encryptByPrivate(RSAPrivateKey rSAPrivateKey, byte[] plainTextData) throws Exception {
		if (rSAPrivateKey == null) {
			throw new Exception("加密私钥为空, 请设置");
		}
		Cipher cipher = null;

		cipher = Cipher.getInstance("RSA", new BouncyCastleProvider());
		cipher.init(Cipher.ENCRYPT_MODE, rSAPrivateKey);
		byte[] output = cipher.doFinal(plainTextData);
		return output;

	}
	

	public byte[] decryptByPrivate(RSAPrivateKey privateKey, byte[] cipherData) throws Exception {
		if (privateKey == null) {
			throw new Exception("解密私钥为空, 请设置");
		}
		Cipher cipher = null;
		cipher = Cipher.getInstance("RSA", new BouncyCastleProvider());
		cipher.init(Cipher.DECRYPT_MODE, privateKey);
		byte[] output = cipher.doFinal(cipherData);
		return output;

	}

	public static byte[] decryptByPublic(RSAPublicKey rSAPublicKey, byte[] cipherData) throws Exception {
		if (rSAPublicKey == null) {
			throw new Exception("解密私钥为空, 请设置");
		}
		Cipher cipher = null;
		cipher = Cipher.getInstance("RSA", new BouncyCastleProvider());
		cipher.init(Cipher.DECRYPT_MODE, rSAPublicKey);
		byte[] output = cipher.doFinal(cipherData);
		return output;
	}
	

	/**
	 * 私钥加密
	 * @param privateKeypath
	 * @param value
	 * @return
	 * @throws Exception
	 */
	private  static String encryptByPrivate(String privateKeypath,String value) throws Exception {
		ClassPathResource classPathResource = new ClassPathResource(privateKeypath);
		InputStream inputStream = classPathResource.getInputStream();
		RSAPrivateKey privateKey=loadPrivateKey_pkcs_1(inputStream);
		// 加密
		byte[] cipher = encryptByPrivate(privateKey,value.getBytes());
		return Base64.getEncoder().encodeToString(cipher);
	}
	
	/**
	 * 公钥解密
	 * @param publicKeypath
	 * @param value
	 * @return
	 * @throws Exception
	 */
	private  static String decryptByPublic(String publicKeypath,String value) throws Exception {
		ClassPathResource classPathResource = new ClassPathResource(publicKeypath);
		InputStream inputStream = classPathResource.getInputStream();
		RSAPublicKey publicKey=loadPublicKey(inputStream);
		// 解密
		byte[] valueByte = Base64.getDecoder().decode(value);
		byte[] plainText = decryptByPublic(publicKey,valueByte);
		String res=new String(plainText,"utf-8");
		return res;
	}
	
	
	public static void main(String[] args) throws Exception {
		
		String privateKeypath="2048/rsa_private_key.pem";
		String value="{maxtags:30000}";
		String val=encryptByPrivate(privateKeypath,value);
		System.out.println(val);
		
		
		String publicKeypath="2048/rsa_public_key.pem";
		String resval=decryptByPublic(publicKeypath,val);
		System.out.println(resval);
			
	}
	


}